#ifndef SPW_TUPLE_H_
#define SPW_TUPLE_H_
#include <type_traits>
#include <utility/spw_pair_in.h>
#include <utility/spw_move_in.h>
namespace spwstd{
namespace spwuti{

// 可以定义移动操作
// 不支持= {}，initializer list初始化
// tuple_impl
template<typename...>
struct TupleImpl_in;

template<>
struct TupleImpl_in<>{
};

template<typename Head, typename... Tail>
struct TupleImpl_in<Head, Tail...>
    : public TupleImpl_in<Tail...>
{
    using Inherited = TupleImpl_in<Tail...>;

    Head head_;

    // 继承类可以隐式转化为基类
    Inherited& GetTail() { return (*this); }
    const Inherited& GetTail() const { return (*this); }

    constexpr TupleImpl_in(): Inherited{}, head_{} {}
    // add_c_r保证是const&避免一次复制
    explicit TupleImpl_in(const Head& h, 
            const Tail&... t)
        : Inherited{t...}, head_{h} {}

    template<typename... Vs>
    constexpr 
    TupleImpl_in(const TupleImpl_in<Vs...>& other) 
        : Inherited{other.GetTail()}, head_{other.head_} {}

    constexpr
    TupleImpl_in(const TupleImpl_in& other)
        : Inherited{other.GetTail()}, head_{other.head_} {}

    template<typename... Vs>
    TupleImpl_in& operator=(const TupleImpl_in<Vs...>& other) 
    {
        head_ = other.head_;
        GetTail() = other.GetTail();
        return *this;
    }

    TupleImpl_in& operator=(const TupleImpl_in& other)
    {
        head_ = other.head_;
        GetTail() = other.GetTail();
        return *this;
    }

protected:
    void Swap_in(TupleImpl_in& other) {
        spwuti::swap(*this, other);
    }
};

template<typename... Elems>
class Tuple: public TupleImpl_in<Elems...>
{
    using Inherited = TupleImpl_in<Elems...>;
public:
    // 默认构造，当没有传入形参时
    constexpr Tuple(): Inherited{} {}

    explicit constexpr Tuple(const Elems&... elems)
        : Inherited(elems...) {}
    
    // Inherited是基础类，所以继承类other可以赋值给Inherited
    constexpr
    Tuple(const Tuple& other): Inherited{other} {}

    Tuple& operator=(const Tuple& other) {
        static_cast<Inherited&>(*this) = other;
        return *this;
    }

    template<typename... Vs>
    constexpr explicit
    Tuple(const Tuple<Vs...>& other): Inherited{other} {}

    template<typename... Vs>
    Tuple& operator=(const Tuple<Vs...>& other) {
        static_cast<Inherited&>(*this) = static_cast<const TupleImpl_in<Vs...>>(other);
        return *this;
    }

    void Swap(Tuple& other) {
        Inherited::Swap_in(other);
    }

    auto GetHead() { return this->head_; }
    const auto& GetHead() const { return this->head_; }

    // 继承类可以隐式转换为基类
    Inherited& GetImpl() { return *this; }
    const Inherited& GetImpl() const { return *this; }
};

// 特例化，无模板参数时
template<>
class Tuple<>{
public:
    void Swap(Tuple& ) {}
};

// 特例化，2参数，可以用pair转换
template<typename T1, typename T2>
class Tuple<T1, T2>: TupleImpl_in<T1, T2>
{
    using Inherited = TupleImpl_in<T1, T2>;
public:
    constexpr Tuple(): Inherited{} {}

    explicit constexpr Tuple(const T1& a, const T2& b)
        : Inherited{a, b} {}

    constexpr Tuple(const Tuple& other): Inherited{other} {}

    Tuple& operator=(const Tuple& other) {
        static_cast<Inherited&>(*this) = other;
        return *this;
    }

    // pair赋值
    template<typename U1, typename U2>
    constexpr explicit Tuple(const Pair<U1,U2>& other)
        : Inherited{
            TupleImpl_in<const U1&, const U2&>
        {other.first_, other.second_}} {}

    template<typename U1, typename U2>
    Tuple& operator=(const Pair<U1,U2>& other)
    {
        this->head_ = other.first_;
        this->GetTail() = other.second_;
        return *this;
    }

    // 可以转换
    template<typename U1, typename U2>
    constexpr explicit Tuple(const Tuple<U1, U2>& other): Inherited{other} {}

    auto GetHead() { return this->head_; }
    const auto& GetHead() const { return this->head_; }

    Inherited& GetImpl() { return *this; }
    const Inherited& GetImpl() const { return *this; }

    template<typename U1, typename U2>
    Tuple& operator=(const Tuple<U1,U2>& other)
    {
        static_cast<Inherited&>(*this) = other;
        return *this;
    }

    void Swap(Tuple& other) {
        Inherited::Swap_in(other);
    }
};

// 逻辑比较
//
/// ==, 类型并且值也相等时，返回true
/// 否则返回false
/// 不支持隐式转换
bool operator==(const Tuple<>&, const Tuple<>&)
{
    return true;
}

// 只有0类型数量TupleImpl_in才可以传入
template<typename...Ts, 
    typename = typename std::enable_if<sizeof...(Ts)==0>::type>
bool operator==(const TupleImpl_in<Ts...>&, const TupleImpl_in<Ts...>&)
{
    return true;
}

/// #关注类型是否相等, 类型不等返回false
template<typename Head1, typename... Tail1,
         typename Head2, typename... Tail2,
         typename = typename std::enable_if<
            sizeof...(Tail1)==sizeof...(Tail2)>::type 
        >
bool operator==(const Tuple<Head1, Tail1...>& a, 
                const Tuple<Head2, Tail2...>& b) {
    return (a.GetImpl() == b.GetImpl());
}

template<typename... Vs1, typename... Vs2> 
bool operator==(const Tuple<Vs1...>&,
                const Tuple<Vs2...>&) {
    return false;
}

/// # 类型数量相等，关注比较数值, 和类型
template<typename Head1, typename... Tail1,
         typename Head2, typename... Tail2>
bool operator==(const TupleImpl_in<Head1, Tail1...>& a, 
                const TupleImpl_in<Head2, Tail2...>& b) {
    return std::is_same<Head1, Head2>::value ?
           a.head_ == b.head_ &&
           a.GetTail() == b.GetTail() : false;
}

/// !=
template<typename... Vs1, typename... Vs2> 
bool operator!=(const Tuple<Vs1...>& a,
                const Tuple<Vs2...>& b) {
    return !(a==b);
}

/// <
bool operator<(const Tuple<>&, const Tuple<>&)
{
    return false;
}

template<typename...Ts, 
    typename = typename std::enable_if<sizeof...(Ts)==0>::type>
bool operator<(const TupleImpl_in<Ts...>&, const TupleImpl_in<Ts...>&)
{
    return false;
}

template<typename Head1, typename... Tail1,
         typename Head2, typename... Tail2,
         typename = typename std::enable_if<
            sizeof...(Tail1)==sizeof...(Tail2)>::type >
bool operator<(const Tuple<Head1, Tail1...>& a, 
                const Tuple<Head2, Tail2...>& b) {
    return (a.GetImpl() < b.GetImpl());
}

template<typename Head1, typename... Tail1,
         typename Head2, typename... Tail2,
         typename = typename std::enable_if<std::is_same<Head1, Head2>::value>::type>
bool operator<(const TupleImpl_in<Head1, Tail1...>& a, 
                const TupleImpl_in<Head2, Tail2...>& b) {
    return a.head_ != b.head_ ? a.head_ < b.head_ :
           a.GetTail() < b.GetTail();
}

/// <=
template<typename... Vs1, typename... Vs2> 
bool operator<=(const Tuple<Vs1...>& a,
                const Tuple<Vs2...>& b) {
    return a < b || a == b;
}

/// >
template<typename... Vs1, typename... Vs2> 
bool operator>(const Tuple<Vs1...>& a,
                const Tuple<Vs2...>& b) {
    return !(a<b||a==b);
}
/// >=
template<typename... Vs1, typename... Vs2> 
bool operator>=(const Tuple<Vs1...>& a,
                const Tuple<Vs2...>& b) {
    return !(a < b);
}

// 辅助函数/类
/// tupleSize得到tuple type数量
template<typename T>
struct TupleSize;

template<typename... Vs>
struct TupleSize<Tuple<Vs...>>
{
    // 使用static因为该类使用该value是唯一的, 类似单例模式
    static const int value = sizeof...(Vs);
};

template<typename... Vs>
const int TupleSize<Tuple<Vs...>>::value;

/// tie, 解包tuple或pair. 或创建左值引用的tuple
/// 返回是传入参数引用的tuple
template<typename... Vs>
inline Tuple<Vs&...>
tie(Vs&... args) {
    return Tuple<Vs&...>(args...);
}

/// swap
template<typename... Vs>
inline void
swap(Tuple<Vs...>& x, Tuple<Vs...>& y) {
    x.Swap(y);
}

/// make_tuple 得到传入参数，退化类型的tuple
/// 退化cv和引用
/// TODO: 如果是reference_warp<>则还是引用
template<typename... Vs>
inline Tuple<Vs ...>
makeTuple(Vs... args) {
    return Tuple<Vs...>(args...);
}

/// get
template<unsigned Idx>
struct TupleGet_in{
    template<typename Head, typename... Tail>
    static const auto& get(const TupleImpl_in<Head, Tail...>& t) {
        // 每次递归一个get，向前移动一位
        // 比如，idx为2时，获得第3个元素
        // TupleGet<2-1>::get 移到第二位
        // TupleGet<1-1>::get 移到第三位
        return TupleGet_in<Idx-1>::get(t.GetTail());
    }
};

template<>
struct TupleGet_in<0> {
    template<typename Head, typename... Tail>
    static const Head& get(const TupleImpl_in<Head, Tail...>& t) {
        return t.head_;
    }
};

// 无论传入Tuple是什么限定额类型
// 返回类型为auto，为普通类型，退化cv和引用
template<unsigned Idx, typename... Vs>
auto get(const Tuple<Vs...>& t){
    return TupleGet_in<Idx>::get(t.GetImpl());
}

} // namespace spwuti
} // namespace spwstd
#endif // SPW_TUPLE_H_
